﻿using System;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using System.Collections.Generic;

//modbus assemblies
using Modbus.Data;
using Modbus.Device;
using Modbus.Utility;

namespace iPower
{
    class ModbusQuery
    {
        // Instance Variables
        string portName;
        int baudRate;
        Parity parity;
        int dataBits;
        StopBits stopBits;

        SerialPort port;

        // Default Constuctor
        public ModbusQuery() { }

        // Create and Open Serial Port
        public void createPort(string portName, int baudRate, string parity, int dataBits, int stopBits, List<string> debugList )
        {
            this.portName = portName;
            this.baudRate = baudRate;
            this.dataBits = dataBits;

            switch(parity)
            {
                case "even" :
                    this.parity = Parity.Even;            
                break;

                case "odd"  :
                    this.parity = Parity.Odd;
                break;
    
                case "none" :
                    this.parity = Parity.None;
                break;
            }//switch

            switch(stopBits)
            {
                case 1  :
                    this.stopBits = StopBits.One;
                break;

                case 2  :
                    this.stopBits = StopBits.Two;
                break;
            }//switch

            // Try to Open the port
            try
            {
                // Create the port, pass values to constructor
                port = new SerialPort(this.portName, this.baudRate, this.parity, this.dataBits, this.stopBits);

                // Make sure port is not Opened Already
                if (port.IsOpen != true)
                {
                    // Open Port
                    port.Open();
                }//if

            } //try
            catch(Exception ex)
            {
                if (debugList.Count < 100)
                {
                    // Add Exception to List Box
                    debugList.Add(ex.ToString());
                } //if
                else
                {
                    // Clear List Box - to many Items
                    debugList.Clear();

                    // Add Exception to List Box
                    debugList.Add(ex.ToString());
                } //else
            } //catch
        } //openPort

        // Close Serial Port
        public void closePort()
        {
            port.Close();
        } //closePort

        // Get Modbus Values
        public double getMobus(byte slaveID, ushort startAddr, string dataType,int scale,int timeout,int retry , List<string> debugList)
        {
            // Method Variables
            ushort[] data;
            double retValue = 0;
            byte[] byte_array = new byte[4];

            try
            {
                IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(port);

                // Set Timeout Parameters
                master.Transport.ReadTimeout = timeout;
                master.Transport.Retries = retry;

                switch (dataType)
                {
                    case "INT":
                        data = master.ReadHoldingRegisters(slaveID, startAddr, 1);
                        retValue = (double)data[0];
                        break;

                    case "LONG":
                        data = master.ReadHoldingRegisters(slaveID, startAddr, 2);
                        retValue = (double)((data[0] << 16) + data[1]);
                        break;

                    case "INT/SCALE":
                        data = master.ReadHoldingRegisters(slaveID, startAddr, 1);

                        // div/0 protection
                        if (scale != 0)
                        {
                            retValue = (double)data[0] / scale;
                        } //if
                        else
                        {
                            retValue = (double)data[0] / 1;
                        } //else
                        break;

                    case "LONG/SCALE":

                        data = master.ReadHoldingRegisters(slaveID, startAddr, 2);

                        // div/0 protection
                        if (scale != 0)
                        {
                            retValue = (double)((data[0] << 16) + data[1]) / scale;
                        } //if
                        else
                        {
                            retValue = (double)((data[0] << 16) + data[1]) / 1;
                        } //else
                        break;

                    case "FLOAT":
                        data = master.ReadHoldingRegisters(slaveID, startAddr, 2);

                        byte_array[0] = (byte)(data[0] & 0xFF);
                        byte_array[1] = (byte)(data[0] >> 8);
                        byte_array[2] = (byte)(data[1] & 0xFF);
                        byte_array[3] = (byte)(data[1] >> 8);

                        retValue = BitConverter.ToSingle(byte_array, 0);
                        break;

                    case "FLOAT/INV"    :
                        data = master.ReadHoldingRegisters(slaveID, startAddr, 2);

                        byte_array[0] = (byte)(data[1] & 0xFF);
                        byte_array[1] = (byte)(data[1] >> 8);
                        byte_array[2] = (byte)(data[0] & 0xFF);
                        byte_array[3] = (byte)(data[0] >> 8);

                        retValue = BitConverter.ToSingle(byte_array, 0);
                        break;
                }//switch

                //Return with Value
                return retValue;
            } //try
            catch (Exception ex)
            {
                if (debugList.Count < 100)
                {
                    // Add Exception to List Box
                    debugList.Add(ex.ToString());
                } //if
                else
                {
                    // Clear List Box - to many Items
                    debugList.Clear();

                    // Add Exception to List Box
                    debugList.Add(ex.ToString());
                } //else
            }//catch

            // If exception - return 0
            return 0;                   
        } //getMobus    
    }//class
} //namespace
